<?php

namespace IYUU\sdk\CoolQ\Domain;

use GroupMemberModel;
use IYUU\sdk\CoolQ\Context;
use IYUU\sdk\CoolQ\Event\Message as EventMessage;
use think\db\exception\DbException;
use UserModel;
use Yaf\Registry;
use function IYUU\sdk\CoolQ\getConfig;
use function IYUU\sdk\CoolQ\getContext;
use function IYUU\sdk\CoolQ\getOneBot;

/**
 * 用户逻辑
 * - 无状态静态类
 * Class User
 * @package IYUU\sdk\CoolQ\Domain
 */
class User
{
    /**
     * 获取群成员列表，写入数据库
     * @param int $group_id
     * @return array
     */
    public static function syncUserTable(int $group_id = 0): array
    {
        $rs = [
            'user_create' => 0,
            'group_create' => 0,
            'user_update' => 0,
            'group_update' => 0,
        ];

        $cq = getOneBot();
        $list = $cq->getGroupMemberList($group_id);
        // 调试日志
        //file_put_contents(runtime_path() . '/initUser.log', __METHOD__ . PP($list, false));
        if ($list && (is_array($list) || is_object($list))) {
            $u_create = 0;
            $g_create = 0;
            $u_update = 0;
            $g_update = 0;
            foreach ($list as $user) {
                try {
                    if (empty($user->user_id) || empty($user->group_id) || $user->group_id !== $group_id) {
                        continue;
                    }
                    // 初始化变量
                    $user_id = $user->user_id;
                    $last_sent_time = $user->last_sent_time ?? 0;
                    $join_time = $user->join_time ?? BOT_REQUEST_TIME;
                    $nickname = trim($user->nickname ?? '') ?? '';
                    $role = trim($user->role ?? '') ?? 'member'; // 群角色
                    if (isset($user->sex)) {
                        $sex = $user->sex === 'unknown' ? 0 : ($user->sex === 'male' ? 1 : 2);
                    } else {
                        $sex = 0;
                    }

                    /**
                     * 1.查用户表得到用户主键（无则创建）
                     */
                    $user = UserModel::where('user_id', $user_id)->findOrEmpty();
                    if ($user->isEmpty()) {
                        // 无此用户，创建
                        $db = [
                            'user_id' => $user_id,
                            'nickname' => $nickname,
                            'sex' => $sex,
                            'subscribe_time' => $join_time,
                            'last_sent_time' => $last_sent_time,
                        ];
                        $user = UserModel::create($db);
                        $u_create++;
                    } else {
                        // 存在，更新
                        $user->nickname = $nickname;
                        $user->sex = $sex;

                        $min = min($join_time, $user->subscribe_time);
                        $user->subscribe_time = $min ? $min : $join_time;

                        $max = max($last_sent_time, $user->last_sent_time);
                        $user->last_sent_time = $max;
                        $user->save();
                        $u_update++;
                    }
                    // 用户主键
                    $uid = $user->id;

                    /**
                     * 2.查群成员表（无则创建）
                     */
                    $group = GroupMemberModel::where('uid', $uid)->where('group_id', $group_id)->findOrEmpty();
                    if ($group->isEmpty()) {
                        // 无群成员关系，创建
                        $db = [
                            'uid' => $uid,
                            'group_id' => $group_id,
                            'last_sent_time' => $last_sent_time,
                            'sync_time' => BOT_REQUEST_TIME,
                            'join_time' => $join_time,
                            'role' => $role,
                        ];
                        $group = GroupMemberModel::create($db);
                        $g_create++;
                    } else {
                        // 存在群成员关系，更新
                        $group->role = $role;

                        $max = max($last_sent_time, $group->last_sent_time);
                        $group->last_sent_time = $max;

                        $group->sync_time = BOT_REQUEST_TIME;

                        $min = min($join_time, $group->join_time);
                        $group->join_time = $min;

                        $group->save();
                        $g_update++;
                    }
                    // 销毁对象
                    unset($user, $group);
                } catch (DbException $e) {
                    // 出错啦，通知管理
                    file_put_contents(runtime_path() . '/DbException.log', __METHOD__ . p(getContext()->get(), false), FILE_APPEND);
                    file_put_contents(runtime_path() . '/DbException.log', __METHOD__ . p($e->getMessage(), false), FILE_APPEND);
                }
            }

            // 填充返回值
            $rs = [
                'user_create' => $u_create,
                'group_create' => $g_create,
                'user_update' => $u_update,
                'group_update' => $g_update,
            ];
        }
        return $rs;
    }

    /**
     * 监听 群成员增加{group_increase}事件
     * - 新增用户，更新群成员关系
     *
     * @param int $user_id 加入者QQ号
     * @param int $group_id 群号
     * @param int $self_id 收到事件的机器人QQ号
     */
    public static function listenGroupIncrease(int $user_id, int $group_id = 0, int $self_id = 0)
    {
        if (empty($user_id) || empty($group_id) || empty($self_id)) {
            return;
        }
        /**
         * 1.查用户表得到用户主键（无则创建）
         */
        $user = UserModel::where('user_id', $user_id)->findOrEmpty();
        if ($user->isEmpty()) {
            // 无此用户，创建
            $db = [
                'user_id' => $user_id,
                'subscribe_time' => BOT_REQUEST_TIME
            ];
            $user = UserModel::create($db);
        }
        // 用户主键
        $uid = $user->id;

        /**
         * 2.查群成员表（无则创建）
         */
        $group = GroupMemberModel::where('uid', $uid)->where('group_id', $group_id)->findOrEmpty();
        if ($group->isEmpty()) {
            // 无群成员关系，创建
            $db = [
                'uid' => $uid,
                'group_id' => $group_id,
                'sync_time' => BOT_REQUEST_TIME,
                'join_time' => BOT_REQUEST_TIME,
            ];
            $group = GroupMemberModel::create($db);
        } else {
            // 存在群成员关系，更新
            $group->sync_time = BOT_REQUEST_TIME;
            $group->join_time = BOT_REQUEST_TIME;
            $group->save();
        }
    }

    /**
     * 监听 群成员减少{group_decrease}事件
     * - 更新群成员关系
     *
     * @param int $user_id 加入者QQ号
     * @param int $group_id 群号
     * @param int $self_id 收到事件的机器人QQ号
     */
    public static function listenGroupDecrease(int $user_id, int $group_id = 0, int $self_id = 0)
    {
        if (empty($user_id) || empty($group_id) || empty($self_id)) {
            return;
        }
        /**
         * 1.查用户表得到用户主键
         */
        $user = UserModel::where('user_id', $user_id)->findOrEmpty();
        if ($user->isEmpty()) {
            // 无此用户，返回
            return;
        }
        // 用户主键
        $uid = $user->id;

        /**
         * 2.查群成员表（有则删除）
         */
        $group = GroupMemberModel::where('uid', $uid)->where('group_id', $group_id)->findOrEmpty();
        if (!$group->isEmpty()) {
            // 存在群成员关系，删除
            $group->delete();
        }
    }

    /**
     * 监听用户 最后发言 (可同时监听群消息和私聊消息)
     * - 新增用户，更新群成员关系
     *
     * @param Context $context
     * @param EventMessage $msgObj
     */
    public static function listenLastSpeak(Context $context, EventMessage $msgObj)
    {
        $event = $context->get();
        /**
         * 1.查用户表得到用户主键（无则创建）
         */
        if (empty($event['user_id'])) {
            return;
        }
        $user = UserModel::where('user_id', $event['user_id'])->findOrEmpty();
        if ($user->isEmpty()) {
            // 无此用户，创建
            $db = [
                'user_id' => $event['user_id'],
                'last_sent_time' => BOT_REQUEST_TIME,
                'subscribe_time' => BOT_REQUEST_TIME,
                'last_checkin' => 0
            ];
            $user = UserModel::create($db);
        } else {
            // 存在，更新
            $user->last_sent_time = BOT_REQUEST_TIME;
            $user->save();
        }
        /**
         * 2.把对象放入注册表
         */
        Registry::set(UserModel::Registry, $user);
        // 用户数据存入Session
        $context->setSession(Context::moduleUserSession, $user->toArray());

        /**
         * 3.系统功能：打卡、签到、查询
         */
        // 3.1 成员直接发送查询指令
        if (!empty($event['message']) && ($event['message'] === '查询积分') || ($event['message'] === '积分')) {
            if ($resp = static::buildCheckinResponse(0, $user->continue_checkin ?? 0, $user->credits ?? 0, $user->credits_exchange ?? 0)) {
                // 异步发送查询结果
                $msgObj->sendBack($resp, false, true, 30);
            }
        }
        // 3.2 触发自动签到（成员今天第一次发言，但是未签到）
        if (static::isTodayCheckin($user->last_checkin) === false) {
            if ($resp = static::listenUserCheckin($user)) {
                //$resp .= getConfig('checkin.shop', '');
                // 异步发送签到结果
                $msgObj->sendBack($resp, false, true, 30);
            }
        }

        /**
         * 4.查群成员关系表（无则创建）
         */
        if (empty($event['group_id'])) {
            return;
        }
        // 4.1 用户主键
        $uid = $user->id;
        $group = GroupMemberModel::where('uid', $uid)->where('group_id', $event['group_id'])->findOrEmpty();
        if ($group->isEmpty()) {
            // 4.2 无群成员关系，创建
            $db = [
                'uid' => $uid,
                'group_id' => $event['group_id'],
                'last_sent_time' => BOT_REQUEST_TIME,
                'sync_time' => BOT_REQUEST_TIME,
                'join_time' => BOT_REQUEST_TIME,
            ];
            $group = GroupMemberModel::create($db);
        } else {
            // 4.3 存在群成员关系，更新
            $group->last_sent_time = BOT_REQUEST_TIME;
            $group->sync_time = BOT_REQUEST_TIME;
            $group->save();
        }
    }

    /**
     * 监听用户签到、打卡
     * @param UserModel $user
     * @return string
     */
    private static function listenUserCheckin(UserModel $user): string
    {
        /**
         * 1.判断今日是否已签到
         */
        if (!empty($user->last_checkin) && static::isTodayCheckin($user->last_checkin)) {
            // 今日已签到，错误返回
            return '';
        }

        /**
         * 2.判断是否连续签到
         */
        if (!empty($user->last_checkin) && static::isContinueCheckin($user->last_checkin)) {
            $continue_checkin = $user->continue_checkin + 1;
        } else {
            $continue_checkin = 1;
        }

        // 生成随机签到积分
        $credit = static::randCredit();

        // 持续签到X天额外奖励积分 2022-10-24
        if (static::isExtraCredits($continue_checkin)) {
            $credit += static::getExtraCredits($continue_checkin);
        }

        /**
         * 3.用最佳的更新方式，更新签到数据
         */
        $user->credits = $user->credits + $credit;      // 总积分
        $user->continue_checkin = $continue_checkin;    // 连续签到次数
        $user->last_checkin = BOT_REQUEST_TIME;         // 最后签到时间
        $user->save();

        // 累计积分
        $total = $user->credits;

        // 用户数据存入Session（更新）
        getContext()->setSession(Context::moduleUserSession, $user->toArray());

        // 返回响应
        return static::buildCheckinResponse($credit, $continue_checkin, $total, $user->credits_exchange);
    }

    /**
     * 是否额外奖励连续签到
     * @param int $continue_checkin
     * @return bool
     */
    private static function isExtraCredits(int $continue_checkin): bool
    {
        return 7 <= $continue_checkin;
    }

    /**
     * 额外奖励连续签到的积分值
     * @param int $continue_checkin
     * @return int
     */
    private static function getExtraCredits(int $continue_checkin): int
    {
        switch (true) {
            case 10 >= $continue_checkin:
                return $continue_checkin;
            case 30 >= $continue_checkin:
                return 11;
            case 60 >= $continue_checkin:
                return 12;
            case 120 >= $continue_checkin:
                return 13;
            case 240 >= $continue_checkin:
                return 14;
            default:
                return 15;
        }
    }

    /**
     * 生成签到随机积分值
     * @return int
     */
    private static function randCredit(): int
    {
        return mt_rand(20, 30);
    }

    /**
     * 判断今日是否已签到
     * @param int $last_checkin
     * @return bool     true已签到，false未签
     */
    private static function isTodayCheckin(int $last_checkin = 0): bool
    {
        if (empty($last_checkin)) {
            return false;
        }
        $ago = date('Ymd', $last_checkin);
        $today = date('Ymd', BOT_REQUEST_TIME);
        return $ago === $today;
    }

    /**
     * 判断是否连续签到
     * @param int $last_checkin
     * @return bool     true连续签到，false中断
     */
    private static function isContinueCheckin(int $last_checkin = 0): bool
    {
        if (empty($last_checkin)) {
            return false;
        }
        return date('Ymd', BOT_REQUEST_TIME) === date('Ymd', $last_checkin + 86400);
    }

    /**
     * 打包签到的响应数据
     * @param int $credit 签到积分
     * @param int $continue_checkin 连续签到天数
     * @param int $total 累计积分
     * @param int|null $credits_exchange 消耗积分
     * @return string
     */
    private static function buildCheckinResponse(int $credit = 0, int $continue_checkin = 0, int $total = 0, ?int $credits_exchange = 0): string
    {
        $template = sprintf('[CQ:face,id=63]活跃%d天[CQ:face,id=76]积分%d', $continue_checkin, $total);
        if ($credit > 0) {
            // 持续签到X天额外奖励积分 2022-10-24
            if (static::isExtraCredits($continue_checkin)) {
                $template = sprintf('[CQ:face,id=69]奖励%d(+%d)' . PHP_EOL . $template, $credit, static::getExtraCredits($continue_checkin));
            } else {
                $template = sprintf('[CQ:face,id=69]奖励%d' . PHP_EOL . $template, $credit);
            }
        }
        // 消耗积分不为0
        if ($credits_exchange !== 0) {
            $template .= sprintf(PHP_EOL . '[CQ:face,id=69]消耗：-%d', $credits_exchange);
        }
        return $template;
    }
}
